package cn.edu.xmu.orderpayment.payment.Controller;

import cn.edu.xmu.oomall.core.util.ReturnNo;
import cn.edu.xmu.oomall.core.util.Common;
import cn.edu.xmu.oomall.core.util.ReturnObject;
import cn.edu.xmu.orderpayment.payment.Service.RefundService;
import cn.edu.xmu.orderpayment.payment.constants.Constants;
import cn.edu.xmu.orderpayment.payment.microservice.wechatpayvo.WeChatPayRefundNotifyRetVo;
import cn.edu.xmu.orderpayment.payment.model.bo.Refund;
import cn.edu.xmu.orderpayment.payment.model.po.RefundPo;
import cn.edu.xmu.orderpayment.payment.model.vo.ModificationBody;
import cn.edu.xmu.orderpayment.payment.model.vo.RefundRetVo;
import cn.edu.xmu.orderpayment.payment.model.vo.SimpleAdminUserVo;
import cn.edu.xmu.orderpayment.payment.model.vo.SimpleRefundRetVo;
import cn.edu.xmu.privilegegateway.annotation.aop.Audit;
import cn.edu.xmu.privilegegateway.annotation.aop.LoginName;
import cn.edu.xmu.privilegegateway.annotation.aop.LoginUser;
import cn.edu.xmu.privilegegateway.annotation.util.InternalReturnObject;
import io.swagger.annotations.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.validation.Valid;
import java.time.ZonedDateTime;
import java.time.ZonedDateTime;

import static cn.edu.xmu.oomall.core.util.Common.decorateReturnObject;
import static cn.edu.xmu.privilegegateway.annotation.util.Common.cloneVo;
import static cn.edu.xmu.privilegegateway.annotation.util.Common.setPoModifiedFields;

/**
 * @author  Gaunlin Wang 22920192204282
 * @date  2021-11-15
 */
@Api(value = "支付模块退款部分", tags = "payment")
@RestController // Restful的Controller对象
@RefreshScope
@RequestMapping(value = "/", produces = "application/json;charset=UTF-8")
public class RefundController {

    @Autowired(required = false)
    RefundService refundService;

    private final Logger logger = LoggerFactory.getLogger(RefundController.class);

//    /**
//     * 平台管理员查询退款信息
//     *
//     * @param shopId
//     * @param documentId
//     * @param state
//     * @param beginTime
//     * @param endTime
//     * @param page
//     * @param pageSize
//     * @return 返回类型为SimpleRefund
//     */
//    @ApiOperation(value = "平台管理员查询退款信息")
//    @ApiImplicitParams({
//            @ApiImplicitParam(name = "authorization ", value = "用户token", required = true, dataType = "String", paramType = "header"),
//            @ApiImplicitParam(name = "shopId", value = "管理员id", required = true, dataType = "Integer", paramType = "path"),
//            @ApiImplicitParam(name = "documentId", value = "单据id", required = false, dataType = "Integer", paramType = "query"),
//            @ApiImplicitParam(name = "state", value = "状态", required = false, dataType = "Integer", paramType = "query"),
//            @ApiImplicitParam(name = "beginTime", value = "晚于此支付时间", required = false, dataType = "String", paramType = "query"),
//            @ApiImplicitParam(name = "endTime", value = "早于此支付时间", required = false, dataType = "String", paramType = "query"),
//            @ApiImplicitParam(name = "page", value = "页码", required = false, dataType = "Integer", paramType = "query"),
//            @ApiImplicitParam(name = "pageSize", value = "每页数目", required = false, dataType = "Integer", paramType = "query"),
//    })
//    @ApiResponses({
//            @ApiResponse(code = 0, message = "成功"),
//            @ApiResponse(code = 505, message = "操作的资源不是自己的对象"),
//    })
//    @Audit(departName = "shops")
//    @GetMapping("/shops/{shopId}/refund")
//    public Object adminGetRefundInfo(
//            @PathVariable(value = "shopId", required = true) Long shopId,// 管理员id
//            @RequestParam(name = "documentId", required = false) String documentId, // 单据id
//            @RequestParam(name = "state", required = false) Byte state, // 状态
//            @RequestParam(name = "beginTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") ZonedDateTime beginTime, // 晚于此支付时间 => 注意Format中的格式最后有个Z
//            @RequestParam(name = "endTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") ZonedDateTime endTime, // 早于此支付时间
//            @RequestParam(value = "page", required = false, defaultValue = "1") Integer page, // 页码
//            @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize // 每页数目
//    ){
//        // 如果shopId不为0 说明不是管理员, 返回505错误
//        if(shopId != 0) decorateReturnObject(new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE, "操作的资源id不是自己的对象"));//shopId只能为0 否则返回505错误
//        ReturnObject returnObject = refundService.adminGetRefundInfo(documentId, state, beginTime, endTime, page, pageSize);
//        return decorateReturnObject(returnObject);
//    }
//
//
//    /**
//     * 平台管理员查询退款信息详情
//     *
//     * @param shopId
//     * @param id
//     * @param loginUserId
//     * @param loginUserName
//     * @return 返回类型为Refund型
//     */
//    @ApiOperation(value = "平台管理员查询退款信息详情")
//    @ApiImplicitParams({
//            @ApiImplicitParam(paramType = "header", dataType = "String", name = "authorization", value = "用户Token", required = true),
//            @ApiImplicitParam(paramType = "path", dataType = "Integer", name = "shopId", value = "管理员id", required = true),
//            @ApiImplicitParam(paramType = "path", dataType = "Integer", name = "id", value = "退款id", required = true)
//    })
//    @ApiResponses({
//            @ApiResponse(code = 0, message = "成功"),
//            @ApiResponse(code = 505, message = "操作的资源不是自己的对象"),
//    })
//    @Audit(departName = "shops")
//    @GetMapping("/shops/{shopId}/refund/{id}")
//    @ResponseBody // 为了解决测试过程中 Content type not set 引入
//    public Object adminGetCertainRefundInfo(
//            @PathVariable(value = "shopId", required = true) Long shopId,// 管理员id
//            @PathVariable(name = "id", required = true) Long id, // 退款id
//            @LoginUser Long loginUserId, @LoginName String loginUserName
//    ){
//        if(shopId != 0) return Common.decorateReturnObject(new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE, "操作的资源不是自己的对象"));//校验管理员权限无误后
//        ReturnObject returnObject = refundService.adminGetCertainRefundInfo(id);// 通过退款id查询退款详情
//        return Common.decorateReturnObject(returnObject);
//    }

    @ApiOperation(value = "平台管理员查询退款信息")
    @GetMapping("/shops/{shopId}/refund")
    public Object getRefundInfo(
            @PathVariable Long shopId,
            @RequestParam(required = false) String documentId,
            @RequestParam(required = false) Byte state,

            @RequestParam(value = "beginTime", required = false) @DateTimeFormat(pattern = "uuuu-MM-dd'T'HH:mm:ss.SSSXXX") ZonedDateTime beginTime,
            @RequestParam(value = "endTime", required = false) @DateTimeFormat(pattern = "uuuu-MM-dd'T'HH:mm:ss.SSSXXX") ZonedDateTime endTime,
            @RequestParam(defaultValue = "1") Integer page,
            @RequestParam(defaultValue = "10") Integer pageSize

    ){
        if (0!=shopId){
            ReturnObject ret = new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE);//不是0，说明不是管理员，返回505错误
            return decorateReturnObject(ret);
        }
        ReturnObject res = refundService.adminGetRefundInfo(documentId,state,beginTime,endTime,page,pageSize);
        return decorateReturnObject(Common.getPageRetVo(res, SimpleRefundRetVo.class));
    }

    @ApiOperation(value = "平台管理员查询退款信息详情")
    @GetMapping("/shops/{shopId}/refund/{id}")
    public Object getRefundDetailInfo(@PathVariable Long shopId, @PathVariable Long id){
        if (0!=shopId){
            ReturnObject ret = new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE);//不是0，说明不是管理员，返回505错误
            return decorateReturnObject(ret);
        }
        ReturnObject res = refundService.adminGetCertainRefundInfo(id);
        if(res.getData()!=null){
            Refund refund=(Refund)res.getData();
            RefundRetVo refundRetVo=cloneVo(refund, RefundRetVo.class);
            refundRetVo.setAdjust(new SimpleAdminUserVo(refund.getAdjustId(), refund.getAdjustName()));
            refundRetVo.setCreator(new SimpleAdminUserVo(refund.getCreatorId(), refund.getCreatorName()));
            refundRetVo.setModifier(new SimpleAdminUserVo(refund.getModifierId(), refund.getModifierName()));
            res= new ReturnObject(refundRetVo);
        }
        return decorateReturnObject(res);
    }


    /**
     * 平台管理员修改退款信息
     * 只有未对账的状态才能修改，用于手工挂账处理，否则出507错误
     * @param shopId
     * @param id
     * @param modificationBody
     * @param bindingResult
     * @param loginUserId
     * @param loginUserName
     * @return 返回类型为Refund
     */
    @ApiOperation(value = "平台管理员修改退款信息")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "authorization", value = "用户Token", required = true),
            @ApiImplicitParam(paramType = "path", dataType = "Integer", name = "shopId", value = "管理员id", required = true),
            @ApiImplicitParam(paramType = "path", dataType = "Integer", name = "id", value = "退款id", required = true),
            @ApiImplicitParam(paramType = "body", dataType = "ModificationBody", name = "modificationBody", value = "修改信息", required = true)//包含 state 和 descr
    })
    @ApiResponses({
            @ApiResponse(code = 0, message = "成功"),
            @ApiResponse(code = 505, message = "操作的资源不是自己的对象"),
            @ApiResponse(code = 507, message = "当前状态禁止此操作"),
    })
    @Audit(departName = "shops")
    @PutMapping("/shops/{shopId}/refund/{id}")
    public Object adminUpdateRefundInfo(
            @PathVariable("shopId") Long shopId,//管理员id
            @PathVariable("id") Long id,//退款id
            @Valid @RequestBody ModificationBody modificationBody,
            BindingResult bindingResult, @LoginUser Long loginUserId, @LoginName String loginUserName
    ){
        if(bindingResult.hasErrors()){// 如果bindingResult出错 返回相应错误
            return Common.decorateReturnObject(new ReturnObject(ReturnNo.FIELD_NOTVALID,"传入的RequestBody参数格式不合法"));
        }
        if(shopId != 0){ //校验管理员权限
            return Common.decorateReturnObject(new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE, "操作的资源不是自己的对象"));
        }
        ReturnObject returnObject = refundService.adminUpdateRefundInfo(id, modificationBody, loginUserId, loginUserName);
        return Common.decorateReturnObject(returnObject);
    }

    /**
     * 获得退款单的所有状态
     */
    @ApiOperation(value = "获得退款单的所有状态")
    @ApiResponses({
            @ApiResponse(code = 0, message = "成功"),
    })
    @GetMapping("/refund/states")
    public Object getPaymentStates(){
        ReturnObject ret = refundService.getRefundStates();
        return Common.decorateReturnObject(ret);
    }

    /**
     * 内部API 订单获得退款
     * @param documentId
     * @return
     */
    @GetMapping("internal/document/{documentId}/refund")
    public InternalReturnObject getRefundByDocumentId(
            @PathVariable String documentId
    ){
        ReturnObject res= refundService.getRefundByDocumentId(documentId);

        InternalReturnObject ret = new InternalReturnObject();
        if(res.getData()!=null)
            ret.setData(res.getData());
        ret.setErrno(res.getCode().getCode());
        ret.setErrmsg(res.getErrmsg());
        return ret;
    }

    /**
     * 内部API 订单退款
     * @param documentId
     * @param amount
     * @return
     */
    @PostMapping("internal/document/{documentId}/refund")
    public InternalReturnObject refund(@PathVariable String documentId, @RequestParam Long amount, @RequestParam Byte documentType, @RequestParam String descr){
        ReturnObject res=refundService.createRefund(documentId,amount,documentType,descr);

        InternalReturnObject ret = new InternalReturnObject();
        if(res.getData()!=null)
            ret.setData(res.getData());
        ret.setErrno(res.getCode().getCode());
        ret.setErrmsg(res.getErrmsg());
        return ret;
    }

    /**
     * 内部API 订单全额退款
     * @param documentId
     * @return
     */
    @PostMapping("internal/document/{documentId}/refund/all")
    public InternalReturnObject refundAll(@PathVariable String documentId,@RequestParam Byte documentType,@RequestParam String descr){
        ReturnObject res=refundService.createRefundAll(documentId,documentType,descr);

        InternalReturnObject ret = new InternalReturnObject();
        if(res.getData()!=null)
            ret.setData(res.getData());
        ret.setErrno(res.getCode().getCode());
        ret.setErrmsg(res.getErrmsg());
        return ret;
    }

    /**
     * 内部API查询退款信息
     * @param shopId
     * @param documentId
     * @param state
     * @param beginTime
     * @param endTime
     * @param page
     * @param pageSize
     * @return
     */
    @ApiOperation(value = "内部API查询退款信息")
    @GetMapping("/internal/shops/{shopId}/refund")
    public InternalReturnObject getRefundByStateAndTime(
            @PathVariable Long shopId,
            @RequestParam(required = false) String documentId,
            @RequestParam(required = false) Byte state,
            @RequestParam(value = "beginTime", required = false) @DateTimeFormat(pattern = "uuuu-MM-dd'T'HH:mm:ss.SSSXXX") ZonedDateTime beginTime,
            @RequestParam(value = "endTime", required = false) @DateTimeFormat(pattern = "uuuu-MM-dd'T'HH:mm:ss.SSSXXX") ZonedDateTime endTime,
            @RequestParam(defaultValue = "1") Integer page,
            @RequestParam(defaultValue = "10") Integer pageSize
    ){
        if (0!=shopId){
            return new InternalReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE.getCode(),ReturnNo.RESOURCE_ID_OUTSCOPE.getMessage());
        }
        ReturnObject res = refundService.adminGetRefundInfo(documentId,state,beginTime,endTime,page,pageSize);
        res = Common.getPageRetVo(res, SimpleRefundRetVo.class);

        InternalReturnObject ret = new InternalReturnObject();
        if(res.getData()!=null)
            ret.setData(res.getData());
        ret.setErrno(res.getCode().getCode());
        ret.setErrmsg(res.getErrmsg());
        return ret;
    }

    @ApiOperation(value = "微信退款通知API")
    @PostMapping("/wechat/refund/notify")
    public Object wechatRefundNotify(@RequestBody WeChatPayRefundNotifyRetVo weChatPayRefundNotifyRetVo){
        logger.info(ZonedDateTime.now()+":支付系统收到微信传来的退款回调结果");

//        logger.info(weChatPayPaymentNotifyRetVo);
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Constants.servletRequestAttributes=servletRequestAttributes;
        ReturnObject res = refundService.wechatRefundNotify(weChatPayRefundNotifyRetVo);
        return decorateReturnObject(res);
    }

}
